home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / UUCICO / ULIB.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  22KB  |  603 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    u l i b . c                                                     */
  3. /*                                                                    */
  4. /*    Serial port interface to COMMFIFO.ASM for MS-DOS                */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.  Changes    */
  9. /*    Copyright (c) 1990-1993 by Kendra Electronic Wonderworks;       */
  10. /*    all rights reserved except those explicitly granted by the      */
  11. /*    UUPC/extended license.                                          */
  12. /*--------------------------------------------------------------------*/
  13.  
  14. /*
  15.  *    $Id: ULIB.C 1.9 1993/04/11 00:33:54 ahd Exp $
  16.  *    $Log: ULIB.C $
  17.  * Revision 1.9  1993/04/11  00:33:54  ahd
  18.  * Global edits for year, TEXT, etc.
  19.  *
  20.  * Revision 1.8  1993/04/05  04:35:40  ahd
  21.  * Set/clear abort processing flags in modem.c
  22.  *
  23.  * Revision 1.7  1993/01/23  19:08:09  ahd
  24.  * Don't attempt to detect lost carrier in sread()
  25.  *
  26.  * Revision 1.6  1992/12/30  05:27:11  plummer
  27.  * MS C compile fixes
  28.  * Add CD() to sread
  29.  *
  30.  * Revision 1.5  1992/12/12  16:12:13  ahd
  31.  * Include header file for definition for memory avail routines
  32.  *
  33.  * Revision 1.4  1992/12/07  02:43:20  ahd
  34.  * Improve error message when low memory prevents COMM port install
  35.  *
  36.  * Revision 1.3  1992/11/29  22:09:10  ahd
  37.  * Use sopen() rather than FOPEN() to avoid retries on comm port
  38.  *
  39.  * Revision 1.2  1992/11/21  06:17:42  ahd
  40.  * Delete old (pre-COMMFIFO) autobaud function
  41.  *
  42.  */
  43.  
  44. /*--------------------------------------------------------------------*/
  45. /*                        System include files                        */
  46. /*--------------------------------------------------------------------*/
  47.  
  48. #include <fcntl.h>
  49. #include <io.h>
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <time.h>
  54. #include <share.h>
  55.  
  56. #ifdef __TURBOC__
  57. #include <alloc.h>
  58. #endif
  59.  
  60. /*--------------------------------------------------------------------*/
  61. /*                    UUPC/extended include files                     */
  62. /*--------------------------------------------------------------------*/
  63.  
  64. #include "lib.h"
  65. #include "hlib.h"
  66. #include "ulib.h"
  67. #include "comm.h"
  68. #include "ssleep.h"
  69. #include "catcher.h"
  70.  
  71. /*--------------------------------------------------------------------*/
  72. /*                        Internal prototypes                         */
  73. /*--------------------------------------------------------------------*/
  74.  
  75. static void ShowModem( void );
  76.  
  77. /*--------------------------------------------------------------------*/
  78. /*                          Global variables                          */
  79. /*--------------------------------------------------------------------*/
  80.  
  81. boolean   port_active = FALSE;  /* TRUE = port handler handler active  */
  82.  
  83. static BPS current_bps;
  84. static char current_direct;
  85. static boolean carrierdetect;
  86.  
  87. currentfile();
  88.  
  89. /* IBM-PC I/O routines */
  90.  
  91. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  92.  
  93. /*************** BASIC I/O ***************************/
  94. /* Saltzers serial package (aka Info-IBMPC COM_PKG2):
  95.  * Some notes:  When packets are flying in both directions, there seems to
  96.  * be some interrupt handling problems as far as receiving.  Checksum errors
  97.  * may therefore occur often even though we recover from them.  This is
  98.  * especially true with sliding windows.  Errors are very few in the VMS
  99.  * version.  RH Lamb
  100.  */
  101.  
  102.  
  103. #define  STOPBIT  1
  104. #define LINELOG "LineData.Log"      /* log serial line data here */
  105.  
  106. static int log_handle;
  107. static int logmode = 0;             /* Not yet logging            */
  108. #define WRITING 1
  109. #define READING 2
  110. static FILE *log_stream;
  111. static int com_handle;
  112. static boolean hangup_needed = TRUE;
  113.  
  114. /*--------------------------------------------------------------------*/
  115. /*    o p e n l i n e                                                 */
  116. /*                                                                    */
  117. /*    Open the serial port for I/O                                    */
  118. /*--------------------------------------------------------------------*/
  119.  
  120. int openline(char *name, BPS bps, const boolean direct)
  121. {
  122.    int   value;
  123.  
  124.    if (port_active)              /* Was the port already active?     ahd   */
  125.       closeline();               /* Yes --> Shutdown it before open  ahd   */
  126.  
  127.    printmsg(15, "openline: %s, %d", name, bps);
  128.  
  129.    logmode = 0;
  130.  
  131.    current_direct = (char) (direct ? 'D' : 'M') ;
  132.  
  133.    if (sscanf(name, "COM%d", &value) != 1)
  134.    {
  135.       printmsg(0,"Communications port must be format COMx, was %s",
  136.                 name);
  137.       panic();
  138.    }
  139.  
  140.    com_handle = sopen( name, O_BINARY | O_RDWR, SH_DENYRW );
  141.                                  /* Used soly for lock abilities  */
  142.    if ( com_handle == -1 )
  143.    {
  144.       printerr( name );
  145.       return 1;
  146.    }
  147.  
  148.    select_port(value);
  149.    save_com();
  150.  
  151.    if (!install_com())
  152.    {
  153.       printmsg(0,"Commuications handler install failed; "
  154.                   "probable cause ... memory shortage.");
  155.  
  156. #ifdef __TURBOC__
  157.       printmsg(0,"FAR DOS Memory free = %ld bytes",
  158.                   farcoreleft() );
  159. #endif
  160.  
  161.       return 1;
  162.    }
  163.  
  164.    open_com(bps, current_direct, 'N', STOPBIT, 'D');
  165.    current_bps = bps;
  166.    dtr_on();
  167.    ssleep(2);                 /* Wait two seconds as required by V.24   */
  168.    carrierdetect = FALSE;     /* No modem connected yet                 */
  169.  
  170. /*--------------------------------------------------------------------*/
  171. /*        Log serial line data only if log file already exists        */
  172. /*--------------------------------------------------------------------*/
  173.  
  174.    log_handle = open(LINELOG, O_WRONLY | O_TRUNC | O_BINARY);
  175.    if (log_handle != -1) {
  176.       printmsg(15, "openline: logging serial line data to %s", LINELOG);
  177.       log_stream = fdopen(log_handle, "wb");
  178.    }
  179.  
  180.    port_active = TRUE;     /* record status for error handler */
  181.  
  182.    return 0;
  183.  
  184. } /*openline*/
  185.  
  186.  
  187. /*--------------------------------------------------------------------*/
  188. /*    s r e a d                                                       */
  189. /*                                                                    */
  190. /*    Read from the serial port                                       */
  191. /*                                                                    */
  192. /*    Non-blocking read essential to "g" protocol.  See               */
  193. /*    "dcpgpkt.c" for description.  This all changes in a             */
  194. /*    multi-tasking system.  Requests for I/O should get queued       */
  195. /*    and an event flag given.  Then the requesting process (e.g.     */
  196. /*    gmachine()) waits for the event flag to fire processing         */
  197. /*    either a read or a write.  Could be implemented on VAX/VMS      */
  198. /*    or DG but not MS-DOS.                                           */
  199. /*--------------------------------------------------------------------*/
  200.  
  201. unsigned int sread(char *buffer, unsigned int wanted, unsigned int timeout)
  202. {
  203.    time_t start;
  204.  
  205.    hangup_needed = TRUE;
  206.  
  207.    start = time(nil(time_t)); /* Remember when we started processing */
  208.  
  209. /*--------------------------------------------------------------------*/
  210. /*                  Report the current modem status                   */
  211. /*--------------------------------------------------------------------*/
  212.  
  213.    ShowModem();
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*             Now actually try to read a buffer of data              */
  217. /*--------------------------------------------------------------------*/
  218.  
  219.    for ( ; ; )
  220.    {
  221.       unsigned int pending;
  222.       pending = r_count_pending();
  223.  
  224.       if ( terminate_processing )
  225.       {
  226.          static boolean recurse = FALSE;
  227.          if ( ! recurse )
  228.          {
  229.             printmsg(2,"sread: User aborted processing");
  230.             recurse = TRUE;
  231.          }
  232.          return 0;
  233.       }
  234.  
  235.       printmsg(20, "sread: pending=%d, wanted=%d", pending, wanted);
  236.  
  237.       if (pending >= wanted) {   /* got enough in the buffer? */
  238.          unsigned int i;
  239.          for (i = 0; i < wanted; i++)
  240.          {
  241.             int Received;
  242.  
  243.             Received = receive_com();       /* Get character from com port */
  244.             if ( Received < 0 )
  245.             {
  246.                 printmsg( 10, "sread: recv error" );
  247.                 return 0;                   /* Indicate carrier loss */
  248.             }
  249.             *buffer++ = (char) Received;
  250.             printmsg( 19, "sread: char = %c", Received );
  251.          }
  252.  
  253.          if (log_handle != -1)
  254.          {
  255. #ifdef VERBOSE
  256.             char s[18];
  257. #endif
  258.             buffer -= wanted;
  259.             if (logmode != READING)
  260.             {
  261.                fputs("\nRead:  ", log_stream);
  262.                logmode = READING;
  263.             } /* if */
  264. #ifdef VERBOSE
  265.             for (i = 0; i < wanted; i++) {
  266.                itoa(0x100 | (unsigned) *buffer++, s, 16);
  267.                                              /* Make it printable hex */
  268.                fwrite(s, 1, 2, log_stream);  /* Write hex to the log    */
  269.             } /* for */
  270. #else
  271.             fwrite(buffer, 1, wanted, log_stream);
  272.                                              /* Write data to the log */
  273. #endif
  274.          } /* if (log_handle != -1) */
  275.  
  276.          return pending;
  277.       } else {
  278.          time_t   now     = time(nil(time_t));
  279.          time_t   elapsed = now - start;
  280.  
  281.          if (elapsed >= ((time_t) timeout))
  282.             return pending;
  283.  
  284.          ddelay(0);                    /* Surrender our time slice   */
  285.  
  286.       } /* else */
  287.    } /* for ( ; ; ) */
  288.  
  289. } /*sread*/
  290.  
  291. /*--------------------------------------------------------------------*/
  292. /*    s w r i t e                                                     */
  293. /*                                                                    */
  294. /*    Write to the serial port                                        */
  295. /*--------------------------------------------------------------------*/
  296.  
  297. int swrite(char *data, unsigned int len)
  298. {
  299.    unsigned int i;
  300.  
  301.    hangup_needed = TRUE;
  302.  
  303. /*--------------------------------------------------------------------*/
  304. /*                      Report our modem status                       */
  305. /*--------------------------------------------------------------------*/
  306.  
  307.   ShowModem();
  308.  
  309. /*--------------------------------------------------------------------*/
  310. /*    Introduce a little flow control - Actual line pacing is         */
  311. /*    handled at a lower level                                        */
  312. /*--------------------------------------------------------------------*/
  313.  
  314.    if ( s_count_free() < (int) len )
  315.    {
  316.       int spin = 0;
  317.       static int const max_spin = 20;
  318.  
  319.       int queue_size = s_count_size();
  320.       int queue_free = s_count_free();
  321.  
  322.       if ( (int) len > queue_size )
  323.       {
  324.          printmsg(0,"swrite: Transmit buffer overflow; buffer size %d, "
  325.                     "needed %d",
  326.                queue_size,len);
  327.          panic();
  328.       }
  329.  
  330.       while( ((int)len > queue_free) && (spin < max_spin) )
  331.       {
  332.          int wait;
  333.          int needed;
  334.          int new_free;
  335.  
  336.          needed = max(queue_size/2, ((int)len)-queue_free);
  337.                               /* Minimize thrashing by requiring
  338.                                  big chunks */
  339.  
  340.          wait = (int) ((long) needed * 10000L / (long) current_bps);
  341.                               /* Compute time in milliseconds
  342.                                  assuming 10 bits per byte           */
  343.  
  344.          printmsg(4,"swrite: Waiting %d milliseconds for %d bytes in queue"
  345.                      ", pass %d",
  346.                      wait, needed, spin);
  347.  
  348.          ddelay( wait );      /* Actually perform the wait           */
  349.  
  350.          new_free = s_count_free();
  351.  
  352.          if ( new_free == queue_free )
  353.             spin++;           /* No progress, consider timing out    */
  354.          else
  355.             queue_free = new_free;
  356.                               /* Update our progress                 */
  357.  
  358.       } /* while( (len > queue_free) && spin ) */
  359.  
  360.       if ( queue_free < (int) len )
  361.       {
  362.          printmsg(0,"swrite: Transmit buffer overflow, needed %d bytes",
  363.                      len);
  364.       } /* if ( queue_free < len ) */
  365.       return 0;
  366.  
  367.    } /* if ( s_count_free() < len ) */
  368.  
  369. /*--------------------------------------------------------------------*/
  370. /*            Send the data to the communications package             */
  371. /*--------------------------------------------------------------------*/
  372.  
  373.    for (i = 0; i < len; i++)
  374.       send_com(*data++);
  375.  
  376. /*--------------------------------------------------------------------*/
  377. /*                Log the transmitted data, if desired                */
  378. /*--------------------------------------------------------------------*/
  379.  
  380.    if (log_handle != -1) {
  381. #ifdef VERBOSE
  382.       char s[18];
  383. #endif
  384.       if (logmode != WRITING)
  385.       {
  386.          fputs("\nWrite: ", log_stream);
  387.          logmode = WRITING;
  388.       } /* if */
  389.       data -= len;
  390. #ifdef VERBOSE
  391.       for (i = 0; i < len; i++) {
  392.          itoa(0x100 | (unsigned) *data++, s, 16);
  393.                                         /* Make it printable hex  ahd */
  394.          fwrite(s, 1, 2, log_stream);
  395.       } /* for */
  396. #else
  397.       fwrite(data, 1, len, log_stream);   /* Write data to the log */
  398. #endif
  399.    } /* if */
  400.  
  401. /*--------------------------------------------------------------------*/
  402. /*              Return byte count transmitted to caller               */
  403. /*--------------------------------------------------------------------*/
  404.  
  405.    return len;
  406.  
  407. } /*swrite*/
  408.  
  409.  
  410. /*--------------------------------------------------------------------*/
  411. /*    s s e n d b r k                                                 */
  412. /*                                                                    */
  413. /*    Send a break signal out the serial port                         */
  414. /*--------------------------------------------------------------------*/
  415.  
  416. void ssendbrk(unsigned int duration)
  417. {
  418.  
  419.    printmsg(12, "ssendbrk: %d", duration);
  420.  
  421.    break_com();
  422.  
  423. } /*ssendbrk*/
  424.  
  425.  
  426. /*--------------------------------------------------------------------*/
  427. /*    c l o s e l i n e                                               */
  428. /*                                                                    */
  429. /*    Close the serial port down                                      */
  430. /*--------------------------------------------------------------------*/
  431.  
  432. void closeline(void)
  433. {
  434.    int far *stats;
  435.  
  436.    if (!port_active)
  437.       panic();
  438.  
  439.    port_active = FALSE; /* flag port closed for error handler  */
  440.  
  441.    dtr_off();
  442.    ddelay(500);               /* Required for V.24             */
  443.    close_com();
  444.    restore_com();
  445.    close( com_handle );
  446.  
  447.    if (log_handle != -1) {    /* close serial line log file */
  448.       fclose(log_stream);
  449.       close(log_handle);
  450.    };
  451.  
  452.    stats = com_errors();
  453.    printmsg(3, "Buffer overflows: %-4d", stats[COM_EOVFLOW]);
  454.    printmsg(3, "Receive overruns: %-4d", stats[COM_EOVRUN]);
  455.    printmsg(3, "Break characters: %-4d", stats[COM_EBREAK]);
  456.    printmsg(3, "Framing errors:   %-4d", stats[COM_EFRAME]);
  457.    printmsg(3, "Parity errors:    %-4d", stats[COM_EPARITY]);
  458.    printmsg(3, "Transmit errors:  %-4d", stats[COM_EXMIT]);
  459.    printmsg(3, "DSR errors:       %-4d", stats[COM_EDSR]);
  460.    printmsg(3, "CTS errors:       %-4d", stats[COM_ECTS]);
  461.  
  462. } /*closeline*/
  463.  
  464.  
  465. /*--------------------------------------------------------------------*/
  466. /*    H a n g u p                                                     */
  467. /*                                                                    */
  468. /*    Hangup the telephone by dropping DTR.  Works with HAYES and     */
  469. /*    many compatibles.                                               */
  470. /*    14 May 89 Drew Derbyshire                                       */
  471. /*--------------------------------------------------------------------*/
  472.  
  473. void hangup( void )
  474. {
  475.       if (!hangup_needed)
  476.          return;
  477.       hangup_needed = FALSE;
  478.       dtr_off();              /* Hang the phone up                         */
  479.       ddelay(500);            /* Really only need 250 milliseconds         */
  480.       dtr_on();               /* Bring the modem back on-line              */
  481.       ddelay(2000);           /* Now wait for the poor thing to recover    */
  482.                               /* two seconds is required by V.24           */
  483.       printmsg(3,"hangup: complete.");
  484.       carrierdetect = FALSE;  /* No modem connected yet                    */
  485.  
  486. } /* hangup */
  487.  
  488. /*--------------------------------------------------------------------*/
  489. /*    S I O S p e e d                                                 */
  490. /*                                                                    */
  491. /*    Re-specify the speed of an opened serial port                   */
  492. /*                                                                    */
  493. /*    Dropped the DTR off/on calls because this makes a Hayes drop    */
  494. /*    the line if configured properly, and we don't want the modem    */
  495. /*    to drop the phone on the floor if we are performing             */
  496. /*    autobaud.                                                       */
  497. /*                                                                    */
  498. /*    (Configured properly = standard method of making a Hayes        */
  499. /*    hang up the telephone, especially when you can't get it into    */
  500. /*    command state because it is at the wrong speed or whatever.)    */
  501. /*--------------------------------------------------------------------*/
  502.  
  503. void SIOSpeed(BPS bps)
  504. {
  505.  
  506.    printmsg(4,"SIOSspeed: Changing port speed from %ld BPS to %ld BPS",
  507.                (long) current_bps, (long) bps);
  508.    ioctl_com(0, bps);
  509.  
  510.    ShowModem();
  511.    current_bps = bps;
  512.  
  513. } /*SIOSpeed*/
  514.  
  515. /*--------------------------------------------------------------------*/
  516. /*    f l o w c o n t r o l                                           */
  517. /*                                                                    */
  518. /*    Enable/Disable in band (XON/XOFF) flow control                  */
  519. /*--------------------------------------------------------------------*/
  520.  
  521. void flowcontrol( boolean flow )
  522. {
  523.    printmsg(4,"flowcontrol: Closing port");
  524.    close_com();
  525.    ShowModem();
  526.    printmsg(4,"flowcontrol: Opening port to %sable flow control",
  527.                flow ? "en" : "dis");
  528.    open_com(current_bps, current_direct, 'N', STOPBIT, flow ? 'E' : 'D');
  529.    ShowModem();
  530.  
  531. } /*flowcontrol*/
  532.  
  533. /*--------------------------------------------------------------------*/
  534. /*    G e t S p e e d                                                 */
  535. /*                                                                    */
  536. /*    Report current speed of communications connection               */
  537. /*--------------------------------------------------------------------*/
  538.  
  539. BPS GetSpeed( void )
  540. {
  541.    return current_bps;
  542. } /* GetSpeed */
  543.  
  544. /*--------------------------------------------------------------------*/
  545. /*    C D                                                             */
  546. /*                                                                    */
  547. /*    Report if we have carrier detect and lost it                    */
  548. /*--------------------------------------------------------------------*/
  549.  
  550. boolean CD( void )
  551. {
  552.    boolean online = carrierdetect;
  553.  
  554.    ShowModem();
  555.    carrierdetect = is_cd_high();
  556.  
  557. /*--------------------------------------------------------------------*/
  558. /*    If we previously had carrier detect but have lost it, we        */
  559. /*    report it was lost.  If we do not yet have carrier detect,      */
  560. /*    we return success because we may not have connected yet.        */
  561. /*--------------------------------------------------------------------*/
  562.  
  563.    if (online)
  564.       return carrierdetect && is_dsr_high();
  565.    else
  566.       return is_dsr_high();
  567.  
  568. } /* CD */
  569.  
  570. /*--------------------------------------------------------------------*/
  571. /*    S h o w M o d e m                                               */
  572. /*                                                                    */
  573. /*    Report current modem status                                     */
  574. /*--------------------------------------------------------------------*/
  575.  
  576. #define mannounce(flag, bits, text ) ((flag & bits) ? text : "" )
  577.  
  578. static void ShowModem( void )
  579. {
  580.    static int old_status = 0xDEAD;
  581.    int status;
  582.  
  583.    if ( debuglevel < 4 )
  584.       return;
  585.  
  586.    status = modem_status();
  587.    if (status == old_status)
  588.       return;
  589.  
  590.    printmsg(0, "ShowModem: %#02x%s%s%s%s%s%s%s%s",
  591.       status,
  592.       mannounce(MDM_CD,   status, "\tCarrier Detect"),
  593.       mannounce(MDM_RI,   status, "\tRing Indicator"),
  594.       mannounce(MDM_DSR,  status, "\tData Set Ready"),
  595.       mannounce(MDM_CTS,  status, "\tClear to Send"),
  596.       mannounce(MDM_CDC,  status, "\tCD changed"),
  597.       mannounce(MDM_TRI,  status, "\tRI went OFF"),
  598.       mannounce(MDM_DSRC, status, "\tDSR changed"),
  599.       mannounce(MDM_CTSC, status, "\tCTS changed"));
  600.    old_status = status;
  601.  
  602. } /* ShowModem */
  603.